package alkaid.eis.sys.controller;

import static org.springframework.util.CollectionUtils.isEmpty;
import static org.springframework.util.StringUtils.hasText;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import alkaid.eis.sys.entity.Dict;
import alkaid.eis.sys.entity.DictComparator;
import alkaid.eis.sys.entity.DictDetail;
import alkaid.eis.sys.repository.DictDetailRepository;
import alkaid.eis.sys.repository.DictRepository;
import alkaid.eis.sys.service.DictDetailSpecifications;
import alkaid.eis.sys.service.DictService;
import alkaid.eis.sys.service.DictSpecifications;
import lombok.RequiredArgsConstructor;

/**
 * 字典接口
 * 
 * @author Lucky Yang
 * @since 0.0.1
 */
@RestController
@RequestMapping("/dicts")
@RequiredArgsConstructor
public class DictController {
    private final DictDetailRepository dictDetailRepository;
    private final DictRepository dictRepository;

    private final DictService dictService;

    /**
     * 创建字典
     * 
     * @return
     */
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Long createDict(@RequestBody DictDto dictDto) {
        Dict entity = dictRepository.save(DictMapper.INST.toEntity(dictDto));
        return entity.getId();
    }

    /**
     * 创建字典
     * 
     * @return
     */
    @PostMapping("/{dictId}/details")
    @ResponseStatus(HttpStatus.CREATED)
    public Long createDictDetail(@PathVariable("dictId") Long dictId, @RequestBody DictDetailDto dictDetailDto) {
        DictDetail entity = dictService.saveDictDetail(dictId, DictDetailMapper.INST.toEntity(dictDetailDto));
        return entity.getId();
    }

    /**
     * 更新字典
     * 
     * @return
     */
    @PutMapping("/{dictId}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void updateDict(@PathVariable("dictId") Long dictId, @RequestBody DictDto dictDto) {
        dictService.updateDict(dictId, DictMapper.INST.toEntity(dictDto));
    }

    /**
     * 更新字典明细
     * 
     * @return
     */
    @PutMapping("/details/{dictDetailId}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void updateDictDetail(@PathVariable("dictDetailId") Long dictDetailId,
            @RequestBody DictDetailDto dictDetailDto) {
        dictService.updateDictDetail(dictDetailId, DictDetailMapper.INST.toEntity(dictDetailDto));
    }

    /**
     * 删除字典
     * 
     * @return
     */
    @DeleteMapping("/{dictId}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteDict(@PathVariable("dictId") Long dictId) {
        dictService.deleteDictById(dictId);
    }

    /**
     * 删除字典
     * 
     * @return
     */
    @DeleteMapping("/details/{dictDetailId}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void deleteDictDetail(@PathVariable("dictDetailId") Long dictDetailId) {
        dictDetailRepository.deleteById(dictDetailId);
    }

    @GetMapping("/{dictId}")
    public DictDto getByDictId(@PathVariable("dictId") Long dictId) {
        Dict entity = dictService.findByDictId(dictId);
        return DictMapper.INST.toDto(entity);
    }

    @GetMapping("/details/{dictDetailId}")
    public DictDetailDto getByDictDetailId(@PathVariable("dictDetailId") Long dictDetailId) {
        DictDetail entity = dictService.findByDictDetailId(dictDetailId);
        return DictDetailMapper.INST.toDto(entity);
    }

    @GetMapping
    public Page<DictDto> getPage(@RequestParam(value = "description", required = false) String description,
            @RequestParam(value = "label", required = false) String label, Pageable pageable) {
        Specification<Dict> where = DictSpecifications.empty();
        if (hasText(description)) {
            where = where.and(DictSpecifications.descriptionLike(description));
        }
        if (hasText(label)) {
            where = where.and(DictSpecifications.labelLike(label));
        }

        Page<Dict> page = dictRepository.findAll(where, pageable);
        return page.map(DictMapper.INST::toDto);
    }

    @GetMapping("/{dictId}/detials")
    public List<DictDetailDto> getDetailByDictId(@PathVariable("dictId") Long dictId) {
        Dict dict = dictService.findByDictId(dictId);

        List<DictDetail> entities = dictDetailRepository.findByDict(dict);
        entities.sort(DictComparator.ORDERNO_AND_CODE);
        return DictDetailMapper.INST.toDto(entities);
    }

    @GetMapping("/detials")
    public List<DictDetailFlatDto> getDictFlat(
            @RequestParam(value = "dictCodes", required = false) Set<String> dictCodes,
            @RequestParam(value = "codes", required = false) Set<String> code,
            @RequestParam(value = "enabled", required = false) Boolean enabled) {
        Specification<DictDetail> where = DictDetailSpecifications.empty();
        if (!isEmpty(dictCodes)) {
            where = where.and(DictDetailSpecifications.dictCodeIn(dictCodes));
        }
        if (!isEmpty(code)) {
            where = where.and(DictDetailSpecifications.codeIn(code));
        }
        if (enabled != null) {
            where = where.and(DictDetailSpecifications.enabled(enabled));
        }

        return dictDetailRepository.findAll(where)
                .stream()
                .sorted(DictComparator.DICTID_AND_ORDERNO_AND_CODE)
                .map(DictDetailFlatDto::of)
                .collect(Collectors.toList());

    }

    @GetMapping("/count")
    public long countDict(@RequestParam(value = "code", required = false) String code) {
        Specification<Dict> where = DictSpecifications.empty();
        if (hasText(code)) {
            where = where.and(DictSpecifications.codeEqual(code));
        }
        return dictRepository.count(where);
    }

    @GetMapping("/detials/count")
    public long countDictDetail(@RequestParam(value = "dictId", required = false) String dictId,
            @RequestParam(value = "code", required = false) String code) {
        Specification<DictDetail> where = DictDetailSpecifications.empty();
        if (hasText(dictId)) {
            where = where.and(DictDetailSpecifications.dictIdEqual(dictId));
        }
        if (hasText(code)) {
            where = where.and(DictDetailSpecifications.codeEqual(code));
        }
        return dictDetailRepository.count(where);
    }
}
